#include <stdio.h>
#include <string.h>
#include <iostream>
#include <lua.hpp>
extern "C"
{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
using namespace std;
lua_State *L; // C++与Lua的通信机制

int Average(lua_State *L)
{
    // code3   lua_gettop是取出栈顶的索引值。此时栈顶的索引值大小就是站内元素的个数
    int n = lua_gettop(L);
    double sum = 0;
    // code4 使用循环变量站内所有的元素，通过lua_tonumber取出栈内的值，然后进行相加操作。
    for (int i = 1; i <= n; ++i)
        sum += lua_tonumber(L, i);
    // code5 将运算后的值返还给Lua。把要返回的值再压入栈。此时此时栈内7条数据，参考栈的运行图Log index 2
    lua_pushnumber(L, sum / n); // average
    lua_pushnumber(L, sum);     // sum
    // code6 告诉lua主程序，返回2个值。lua这是可以用参数接受这两个值
    return 2;
}

int main()

{
    L = luaL_newstate(); //这一点与原文方法不一样，5.3.5版本中使用luaL_newstate初始化L，而原文使用lua_open
                         // luaL_openlibs(L);
    luaopen_base(L);
    // code1 lua_register注册函数把Lua函数和C++函数进行绑定。其实就是先用lua_pushcfunction把在c++中定义的函数压如栈中，然后lua_setglobal来设置栈顶的元素对应的值，这样就可以把lua函数和栈顶的c++函数建立引用关系。
    // lua_register(L, "average", Average);
    // code2  加载并执行lua脚本，此时lua中的函数average被执行，同时向栈中压如5个参数。参考栈的运行图Log index 1
    int err = luaL_dofile(L, "../test.lua");
    if (err)
    {
        std::cerr << lua_tostring(L, -1) << std::endl;
        return -1;
    }
    lua_getglobal(L,"testtab");
    cout<<lua_gettop(L)<<endl;
    int index = lua_gettop(L);
    lua_pushnil(L); 
    // 现在的栈：-1 => nil; index => table
    while (lua_next(L, index))
    {
        cout<<lua_gettop(L)<<endl;
        // 现在的栈：-1 => value; -2 => key; index => table
        // 拷贝一份 key 到栈顶，然后对它做 lua_tostring 就不会改变原始的 key 值了
        lua_pushvalue(L, -2);
        cout<<lua_gettop(L)<<endl;
        // 现在的栈：-1 => key; -2 => value; -3 => key; index => table
        const char* key = lua_tostring(L, -1);
        const char* value = lua_tostring(L, -2);
 
        printf("%s => %s\n", key, value);
 
        // 弹出 value 和拷贝的 key，留下原始的 key 作为下一次 lua_next 的参数
        lua_pop(L, 2);
        cout<<lua_gettop(L)<<endl;
        // 现在的栈：-1 => key; index => table
    }
    cout<<lua_gettop(L)<<endl;
    // 现在的栈：index => table （最后 lua_next 返回 0 的时候它已经把上一次留下的 key 给弹出了）
    // 所以栈已经恢复到进入这个函数时的状态

    lua_pop(L, -1);




    // {
    //    std::string compare_func ="function add(a,b)\n print(\"10\")\nreturn a+b\nend\n";
        
    //     luaL_loadbuffer(L,compare_func.c_str(),compare_func.size(),"@cmp_func_def");
    //     lua_pcall(L, 0, 0, 0);

    //     lua_getglobal(L,"add");
    //     lua_pushnumber(L,1);
    //     lua_pushnumber(L,0);
    //     lua_pcall(L,2,1,0);
    //     cout<<"top: "<<lua_gettop(L)<<endl;
    //     cout<<lua_tonumber(L,-1)<<endl;
    // }

    lua_close(L);
    printf("Press enter to exit...\n");
    return 0;
}